<?php

namespace app\company\controller;

use app\common\controller\CompanyController;
use app\common\exception\BaseException;
use app\common\service\annotation\ControllerAnnotation;
use app\common\service\annotation\NodeAnnotation;
use app\common\service\CategoryService;
use app\company\model\ArticleCategories;
use app\company\model\Articles;
use app\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use think\App;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\response\Json;

/**
 * @ControllerAnnotation(title="文档管理")
 */
class Article extends CompanyController
{
    private ArticleCategories $category;

    public function __construct(App $app)
    {
        parent::__construct($app);
        $this->model = new Articles();
        $this->category = new ArticleCategories();
    }

    /**
     * 文档列表
     * @return Json
     * @throws DbException
     */
    public function index()
    {
        $limit = $this->request->get('limit', 10);
        $articles = $this->model->with('category')
            ->order('create_time', 'desc')
            ->paginate($limit);

        return $this->success($articles);
    }

    /**
     * 文档详情
     * @param int $id
     * @return Json
     */
    public function show(int $id)
    {
        try {
            $article = $this->getArticleById($id);
            $article->inc('views')->save();

            return $this->success($article);
        } catch (\Exception $exception) {
            return $this->error('__获取文档详情失败__' . $exception->getMessage());
        }
    }

    /**
     * 文档搜索
     *
     * @return Json
     * @throws DbException
     */
    public function search(): Json
    {
        $keyword = $this->request->get('keyword');
        $startTime = $this->request->get('start_time');
        $endTime = $this->request->get('end_time');
        $limit = $this->request->get('limit', 10);

        $where = [];
        if ($keyword) {
            $where[] = ['title', 'like', "%{$keyword}%"];
        }

        $feedbacks = $this->model->with('category')
            ->where($where)
            ->when($startTime && $endTime, function ($query) use ($startTime, $endTime) {
                $query->whereBetweenTime('create_time', $startTime, $endTime);
            })->order('create_time', 'desc')->paginate($limit);

        return $this->success($feedbacks);
    }

    /**
     * @NodeAnnotation (title="文档新增")
     * @throws BaseException
     */
    public function create(): Json
    {
        $this->checkPost();
        $post = $this->request->post();
        $rule = [
            'title|文档名称' => 'require',
            'author|文档作者' => 'require',
            'article_category_id|文档分类' => 'require',
            'sort|文档排序' => 'require',
            'content|文档内容' => 'require',
        ];
        $this->validate($post, $rule);

        try {
            $this->checkCategory($post['article_category_id']);
            $this->model->save($post);

            return $this->success();
        } catch (\Exception $exception) {
            return $this->error('__添加文档失败__' . $exception->getMessage());
        }
    }

    /**
     * @NodeAnnotation (title="文档修改")
     */
    public function update($id): Json
    {
        $post = $this->request->post();
        $rule = [
            'title|文档名称' => 'require',
            'author|文档作者' => 'require',
            'article_category_id|文档分类' => 'require',
            'sort|文档排序' => 'require',
            'content|文档内容' => 'require',
        ];
        $this->validate($post, $rule);

        try {
            $this->checkCategory($post['article_category_id']);
            $article = $this->getArticleById($id);
            $article->save($post);

            return $this->success();
        } catch (\Exception $exception) {
            return $this->error('__修改文档失败__' . $exception->getMessage());
        }
    }

    /**
     * @NodeAnnotation (title="文档删除")
     *
     * @param $id
     * @return Json
     */
    public function delete($id)
    {
        try {
            $article = $this->getArticleById($id);
            $article->delete();

            return $this->success();
        } catch (\Exception $exception) {
            return $this->error($exception->getMessage());
        }
    }

    /**
     * 根据ID获取文档对象，并检查是否存在
     *
     * @param $id
     * @return Articles|array|\think\Model|Json
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException|Exception
     */
    protected function getArticleById($id): Json|Articles|array|\think\Model
    {
        $article = $this->model->with('category')->find($id);
        if (!$article) {
            throw new Exception('文档不存在');
        }
        return $article;
    }

    /**
     * 文档分类列表
     * @return Json
     */
    public function categories()
    {
        $categories = $this->category->with(['article' => function ($query) {
            $query->field('id, title, article_category_id');
        }])->order('sort', 'asc')
            ->select();
        return $this->success((new CategoryService())->getTreeData($categories));
    }

    /**
     * @NodeAnnotation (title="文档分类新增")
     */
    public function categoriesCreate(Request $request)
    {
        $this->checkPost();
        $post = $request->post();
        $rule = [
            'category_name|分类名' => 'require',
        ];
        $this->validate($post, $rule);

      try {
          // 检查父级分类是否存在
          $this->checkParentCategory($post);
          $this->category->where('category_name', $post['category_name'])
              ->findOrEmpty()
              ->save($post);

            return $this->success();
        } catch (\Exception $exception) {
            return $this->error('__添加文档分类失败__' . $exception->getMessage());
        }
    }

    /**
     * 检查父级分类是否存在
     * @param array $post
     * @return Json|void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws \Exception
     */
    private function checkParentCategory(array $post)
    {
        if (!empty($post['pid'])) {
            if (!$this->category->find($post['pid'])) {
                throw new \Exception('文档父级分类不存在');
            }
        }
    }

    /**
     * @NodeAnnotation (title="文档分类修改")
     */
    public function categoriesUpdate($id): Json
    {
        $category = $this->category->find($id);
        if (!$category) {
            return $this->error('文档分类不存在');
        }

        try {
            $post = $this->request->post();
            $this->checkParentCategory($post);
            if ($category->pid === 0 && isset($post['pid'])) {
                unset($post['pid']);
            }

            $category->where('id', $id)->update($post);

            return $this->success();
        } catch (\Exception $exception) {
            return $this->error('__修改文档分类失败__' . $exception->getMessage());
        }
    }

    /**
     * @NodeAnnotation (title="文档分类删除")
     */
    public function categoriesDelete($id)
    {
        $category = $this->category->find($id);
        if (!$category) {
            return $this->error('文档分类不存在');
        }

        if ($category['pid'] == 0 && $this->category->where('pid', $id)->find()) {
            return $this->error('文档分类下有子分类，请先删除子分类');
        }

        $articleCount = $this->model->where('article_category_id', $id)->count();
        if ($articleCount > 0) {
            return $this->error('当前分类下还有文章，不能删除');
        }

        $category->delete();

        return $this->success('分类删除成功');
    }

    /**
     * 文档分类搜索
     * @return Json
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function categoriesSearch()
    {
        $keyword = $this->request->get('keyword');
        $where = [];
        if ($keyword) {
            $where[] = ['category_name', 'like', "%{$keyword}%"];
        }

        $hitCategories = $this->category->with(['article' => function ($query) {
            $query->field('id, title, article_category_id');
        }])->where($where)
            ->field('id, pid')
            ->select();

        $allCategoryIds = [];
        foreach ($hitCategories as $category) {
            $allCategoryIds[] = $category['id'];
            $parentIds = $this->getAllParentIds($category['id']);
            $allCategoryIds = array_merge($allCategoryIds, $parentIds);
        }
        $allCategoryIds = array_unique($allCategoryIds);

        $allCategories = $this->category->with(['article' => function ($query) {
                $query->field('id, title, article_category_id');
            }])->where('id', 'in', $allCategoryIds)
            ->order('sort', 'asc')
            ->select();

        return $this->success((new CategoryService())->getTreeData($allCategories));
    }

    /**
     * 无限极分类，获取父级分类
     * @param $categoryId
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    private function getAllParentIds($categoryId): array
    {
        $parentIds = [];
        $category = $this->category->find($categoryId);
        if ($category && $category['pid'] > 0) {
            $parentIds[] = $category['pid'];
            $parentIds = array_merge($parentIds, $this->getAllParentIds($category['pid']));
        }
        return $parentIds;
    }

    /**
     * 检测分类是否存在
     * @param int $id
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    private function checkCategory(int $id): void
    {
        $category = $this->category->find($id);
        if (!$category) {
            $this->error('文档分类不存在');
        }
    }
}